package com.tianji.aigc.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.tianji.aigc.entity.ChatSession;
import com.tianji.aigc.mapper.ChatSessionMapper;
import com.tianji.aigc.memory.RedisChatMemory;
import com.tianji.aigc.properties.SessionProperties;
import com.tianji.aigc.service.IChatSessionService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.tianji.aigc.vo.ChatHistoryVO;
import com.tianji.aigc.vo.MessageVO;
import com.tianji.aigc.vo.SessionVO;
import com.tianji.common.exceptions.BadRequestException;
import com.tianji.common.utils.UserContext;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.MessageType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * <p>
 * 对话session 服务实现类
 * </p>
 *
 * @author mr.wu
 * @since 2025-09-02
 */
@Service
public class ChatSessionServiceImpl extends ServiceImpl<ChatSessionMapper, ChatSession> implements IChatSessionService {

    @Autowired
    private SessionProperties sessionProperties;

    /**
     * 新建会话
     *
     * @param num
     * @return
     */
    @Override
    public SessionVO newSession(Integer num) {
        //1.生成唯一会话ID
        String sessionId = IdUtil.fastSimpleUUID(); //唯一的会话ID，使用UUID算法

        //2.新增会话记录
        ChatSession chatSession = ChatSession.builder()
                .userId(UserContext.getUser())//用户id
                .sessionId(sessionId)//会话id
                .build();
        this.save(chatSession);

        //3.随机获取一批热门问题
        List<SessionVO.Example> examples = sessionProperties.getExamples();
        Collections.shuffle(examples);//打乱集合中元素的顺序（随机性）
        List<SessionVO.Example> exampleList = examples.stream().limit(num).toList(); //前端需要的随机N条热门问题列表

        //4.封装响应结果数据
        SessionVO sessionVO = SessionVO.builder()
                .sessionId(sessionId)//会话id
                .title(sessionProperties.getTitle())//默认标题
                .describe(sessionProperties.getDescribe())//默认描述
                .examples(exampleList)//随机问题
                .build();

        return sessionVO;
    }


    /**
     * 热门问题
     *
     * @param num
     * @return
     */
    @Override
    public List<SessionVO.Example> hotExampleList(Integer num) {
        List<SessionVO.Example> examples = sessionProperties.getExamples();
        Collections.shuffle(examples);//打乱集合中元素的顺序（随机性）
        List<SessionVO.Example> exampleList = examples.stream().limit(num).toList(); //前端需要的随机N条热门问题列表
        return exampleList;
    }

    @Autowired
    private RedisChatMemory redisChatMemory;

    /**
     * 查询会话详情（查询redis里每个会话对应的多轮对话消息列表）
     *
     * @param sessionId
     * @return
     */
    @Override
    public List<MessageVO> getMessageList(String sessionId) {
        //获取对话ID
        String conversationId = UserContext.getUser() + ":" + sessionId;

        //根据对话ID查询redis中存储的消息列表
        List<Message> messageList = redisChatMemory.get(conversationId, 100);

        //消息类型转换
        List<MessageVO> messageVOList = messageList.stream()
                .filter(x->x.getMessageType().equals(MessageType.USER) || x.getMessageType().equals(MessageType.ASSISTANT))
                .map(x -> MessageVO.builder()
                        .type(x.getMessageType())
                        .content(x.getText())
                        .build())
                .toList();

        return messageVOList;
    }

    @Override
    public Map<String, List<ChatHistoryVO>> getChatSessionHistory() {
        //1.查询用户最近30条历史会话记录 select * from chat_session where user_id=? order by update_time desc limit 30
        List<ChatSession> chatSessionList = this.lambdaQuery()
                .eq(ChatSession::getUserId,UserContext.getUser())
                .orderByDesc(ChatSession::getUpdateTime)
                .last("limit 30")
                .list();

        //2.数据类型转换ChatSession->ChatHistoryVo
        List<ChatHistoryVO> chatHistoryVOList = BeanUtil.copyToList(chatSessionList, ChatHistoryVO.class);

        //3.将ChatHistoryVO集合数据处理后转为Map
        Map<String,List<ChatHistoryVO>> resultMap = CollStreamUtil.groupByKey(chatHistoryVOList,vo ->{
            LocalDate updateDate = vo.getUpdateTime().toLocalDate();
            LocalDate now = LocalDate.now();
            long between = Math.abs(ChronoUnit.DAYS.between(updateDate, now));
            String key = "";
            if(between<1) {
                key = "当天";
            } else if(between<=30) {
                key = "最近30天";
            } else if(between<=365) {
                key = "最近1年";
            } else {
                key = "1年以上";
            }
            return key;
        });
        return resultMap;
    }

    /**
     * 更新会话记录中第一次对话的标题
     *
     * @param userId
     * @param sessionId
     * @param question
     */
    @Async
    @Override
    public void updateSessionTitle(Long userId, String sessionId, String question) {
//        try {
//            TimeUnit.SECONDS.sleep(30);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }

        //1.查询会话记录判断是否存在
        ChatSession chatSession = this.lambdaQuery()
                .eq(ChatSession::getUserId, userId)
                .eq(ChatSession::getSessionId, sessionId)
                .one();
        if(chatSession==null) {
            throw new BadRequestException("会话不存在无法更新");
        }

        //2.更新用户会话记录里的标题（第一次对话的问题）
        this.lambdaUpdate()
                .eq(ChatSession::getUserId, userId)
                .eq(ChatSession::getSessionId, sessionId)
                //当原来的标题非空值，才更新update时间
                .set(StrUtil.isNotBlank(chatSession.getTitle()),ChatSession::getUpdateTime, LocalDateTime.now())
                //当原来标题为空时，才更新标题
                .set(StrUtil.isBlank(chatSession.getTitle()), ChatSession::getTitle, question)
                .update();
    }
}
